package com.example.robertluozizhao.framecollectdemo.view.opengl;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.os.SystemClock;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
 * Created by Lzz on 3/30/2020.
 */

public class MyGLRenderer implements GLSurfaceView.Renderer {

    private Triangle mTriangle;

    //OG001-004-001 定义投影  mMVPMatrix is an abbreviation for "Model View Projection Matrix"
    private final float[] mMVPMatrix = new float[16];
    private final float[] mProjectionMatrix = new float[16];
    private final float[] mViewMatrix = new float[16];

    private float[] mRotationMatrix = new float[16];

    /*当GLSurfaceView被创建时，会调用一次，用于设置view的OpenGL ES环境*/
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // 设置背景的颜色
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    }

    /*每次绘制图像的时候都会调用这个方法*/
    @Override
    public void onDrawFrame(GL10 gl) {
        // 重绘背景颜色
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        //OG001-003-005 绘制
        mTriangle.draw();


        /*****************OG001-004-002 定义相机视图****************/
        // 设置相机的位置 (视图矩阵)
        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

        // 计算投影和视图变换
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);

        // 绘制形状
        mTriangle.draw(mMVPMatrix);


        /*****************OG001-005  旋转图形****************/
        float[] scratch = new float[16];
        // 为三角形创建一个旋转变化
        long time = SystemClock.uptimeMillis() % 4000L;
        float angle = 0.090f * ((int) time);
        Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, -1.0f);
        // 把旋转矩阵合并到投影和相机矩阵
        // Note that the mMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
        // 画三角形
        mTriangle.draw(scratch);




        /****************************OG001-006-003 提供旋转角度方法**************************/
        // Create a rotation for the triangle
        // long time = SystemClock.uptimeMillis() % 4000L;
        // float angle = 0.090f * ((int) time);
        Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);

        // Combine the rotation matrix with the projection and camera view
        // Note that the mMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);

        // Draw triangle
        mTriangle.draw(scratch);


    }


    /*当几何图形变化时，会调用此方法，例如，当手机屏幕大小变化时*/
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);

        // OG001-002 初始化一个三角形
        mTriangle = new Triangle();

        //OG001-004 应用投影和相机视图
        /**
         * 投影 - 这种变化根据所在的GLSurfaceView的宽和高调整对象的坐标.
         * 如果没有此变化，对象会被不规则的视口扭曲。投射变换一般只需要在OpenGL view创建或者发生变化时调用，代码卸载renderer的onSurfaceChanged()方法中
         *
         * 相机视图 - 次变换是基于一个虚拟相机的位置调整对象的坐标.
         * 注意OpenGL ES并没有定义一个真的相机对象，而是提供了一些工具方法变换绘制对象的显示来模拟一个相机。
         * 一个相机视图的变换只可能在创建GLSurfaceView时调用，或者根据用户动作动态调用
         */
        float ratio = (float) width / height;
        //根据GLSurfaceView的宽和高来计算转换矩阵  此投影矩阵在onDrawFrame()中将应用到对象的坐标
        Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

    }


    /**
     *
     * OG001-003-002 编译着色器的代码工具类
     *
     * 着色器(shader)语言需要编译到OpenGL ES环境中，为了编译着色器的代码，需要在你的Renderer类中创建一个工具类方法：
     * @param type
     * @param shaderCode
     * @return
     */
    public static int loadShader(int type, String shaderCode){

        // 创建一个vertex shader 类型 (GLES20.GL_VERTEX_SHADER)
        // 或者一个 fragment shader 类型(GLES20.GL_FRAGMENT_SHADER)
        int shader = GLES20.glCreateShader(type);

        // 将源码添加到shader并编译
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);

        return shader;
    }



    /***********************OG001-006-002 提供旋转角度方法**********************/
    public volatile float mAngle;//旋转角度

    public float getAngle() {
        return mAngle;
    }

    public void setAngle(float angle) {
        mAngle = angle;
    }

}
